﻿namespace NullObjExpml
{
    using System;
    using System.Data.SqlTypes;

    /// <summary>
    /// Class which describes contact (with hard null)
    /// </summary>
    public class Contact : IAssignable, INullable
    {
        #region Constructors

        private Contact(bool hasNull)
        {
            m_null = hasNull;
        }

        public Contact()
            : this(string.Empty, string.Empty)
        {
        }

        public Contact(string phoneNumber, string email)
        {
            m_PhoneNumber = phoneNumber;
            m_Email = email;
        }

        #endregion

        #region Properties

        /// <summary>
        /// PhoneNumber
        /// </summary>
        /// <exception cref="InvalidOperationException">If someone try to set a value for nullobject</exception>
        public string PhoneNumber
        {
            get { return m_PhoneNumber; }
            set
            {
                if (IsNull)
                    throw new InvalidOperationException();

                m_PhoneNumber = value;
            }
        }

        /// <summary>
        /// Email
        /// </summary>
        /// <exception cref="InvalidOperationException">If someone try to set a value for nullobject</exception>
        public string Email
        {
            get { return m_Email; }
            set
            {
                if (IsNull)
                    throw new InvalidOperationException();

                m_Email = value;
            }
        }

        #endregion

        #region IAssignable Implementation

        /// <summary>
        /// Content transfer
        /// </summary>
        /// <param name="obj">Object that takes content</param>
        /// <exception cref="ArgumentNullException">If object, that takes content is a null object </exception>
        /// <exception cref="NotSupportedException">If object, that takes content isn't supported by method</exception>
        /// <exception cref="InvalidOperationException">If current object is nullable</exception>
        public void AssignTo(object obj)
        {
            if (IsNull)
                throw new InvalidOperationException();

            if (obj == null)
                throw new ArgumentNullException();

            if (obj is Contact && ((Contact)obj).IsNull)
                throw new ArgumentNullException();

            if (obj is Contact)
            {
                Contact c = obj as Contact;
                c.Email = Email;
                c.PhoneNumber = PhoneNumber;

                return;
            }

            throw new NotSupportedException();
        }

        #endregion

        #region INullable Implementation

        public bool IsNull
        {
            get { return m_null; }
        }

        public static Contact Null
        {
            get { return new Contact(true); }
        }

        #endregion

        #region Private Fields

        private readonly bool m_null = false;
        private string m_PhoneNumber = default(string);
        private string m_Email = default(string);

        #endregion
    }
}
